﻿/*
 * BitmapBlock
 * 
 * initial implementation : 3.12.2008
 *
 * Copyright (c) Adam Sida, asida@centrum.cz.
 * All rights reserved.
 * 
 * for license see Petra.Gis.License.txt
 */
using System;
using System.IO;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Runtime.InteropServices;

namespace Petra.Gis.ImagingServices.Tiff
{

  /// <summary>
  /// represents single block of data within tiff file
  /// as BitmapSource
  /// </summary>
  public abstract partial class BitmapBlock : BitmapSource
  {

    //protected TiffReader _tiffReader;
    //protected bool _decodeBilevelAs8bpp;
    //protected Metadata _metadata;
    protected int _blockId; //index of block in frame block diagram (single dimensional) 0 - N


    protected BitmapBlock(BlockBitmapSource parent, Int32Rect bounds, int blockId)
    {
      if (parent == null || bounds == null || blockId < 0)
        throw new ArgumentException("null bounds or parent null, or blockId out of range");

      if(blockId > parent.Blocks.Length - 1)
        throw new ArgumentException("blockId out of parent range");

      _parent = parent;
      _bounds = bounds;
      _blockId = blockId;
    }


    #region Freezable

    /// <summary>
    ///     Creates an instance of a BitmapBlock.
    /// </summary>
    /// <returns>
    ///     The new instance.
    /// </returns>
    /// <remarks>
    ///     The default implementation uses reflection to create a new
    ///     instance of this type.  Derived classes may override this
    ///     method if they wish to provide a more performant
    ///     implementation, or if their type does not have a public
    ///     default constructor.
    /// </remarks>
    protected override Freezable CreateInstanceCore()
    {
      return (Freezable)Activator.CreateInstance(this.GetType());
    }

    /// <summary>
    ///     Copies data into a cloned instance.
    /// </summary>
    /// <param name="source">
    ///     The original instance to copy data from.
    /// </param>
    /// <remarks>
    ///     When Freezable is cloned, WPF will make deep clones of all
    ///     writable, locally-set properties including expressions. The
    ///     property's base value is copied -- not the current value. WPF
    ///     skips read only DPs.
    ///     
    ///     If you derive from this class and have additional non-DP state
    ///     that should be transfered to copies, you should override the
    ///     CopyCommon method.
    /// </remarks>
    protected sealed override void CloneCore(Freezable source)
    {
      base.CloneCore(source);

      BitmapBlock customBitmapSource = (BitmapBlock)source;
      CopyCore(customBitmapSource, /*useCurrentValue*/ false, /*willBeFrozen*/ false);
    }

    /// <summary>
    ///     Copies data into a cloned instance.
    /// </summary>
    /// <param name="source">
    ///     The original instance to copy data from.
    /// </param>
    /// <remarks>
    ///     When a Freezable's "current value" is cloned, WPF will make
    ///     deep clones of the "current values" of all writable,
    ///     locally-set properties. This has the effect of resolving
    ///     expressions to their values. WPF skips read only DPs.
    ///     
    ///     If you derive from this class and have additional non-DP state
    ///     that should be transfered to copies, you should override the
    ///     CopyCommon method.
    /// </remarks>
    protected sealed override void CloneCurrentValueCore(Freezable source)
    {
      base.CloneCurrentValueCore(source);

      BitmapBlock customBitmapSource = (BitmapBlock)source;
      CopyCore(customBitmapSource, /*useCurrentValue*/ true, /*willBeFrozen*/ false);
    }

    /// <summary>
    ///     Copies data into a cloned instance.
    /// </summary>
    /// <param name="source">
    ///     The original instance to copy data from.
    /// </param>
    /// <remarks>
    ///     Freezable.GetAsFrozen is semantically equivalent to
    ///     Freezable.Clone().Freeze(), except that you can avoid copying
    ///     any portions of the Freezable graph which are already frozen.
    ///     
    ///     If you derive from this class and have additional non-DP state
    ///     that should be transfered to copies, you should override the
    ///     CopyCommon method.
    /// </remarks>
    protected sealed override void GetAsFrozenCore(Freezable source)
    {
      base.GetAsFrozenCore(source);

      BitmapBlock customBitmapSource = (BitmapBlock)source;
      CopyCore(customBitmapSource, /*useCurrentValue*/ false, /*willBeFrozen*/ true);
    }

    /// <summary>
    ///     Copies data into a cloned instance.
    /// </summary>
    /// <param name="source">
    ///     The original instance to copy data from.
    /// </param>
    /// <remarks>
    ///     Freezable.GetCurrentValueAsFrozen is semantically equivalent to
    ///     Freezable.CloneCurrentValue().Freeze(), except that WPF will
    ///     avoid copying any portions of the Freezable graph which are
    ///     already frozen.
    ///     
    ///     If you derive from this class and have additional non-DP state
    ///     that should be transfered to copies, you should override the
    ///     CopyCommon method.
    /// </remarks>
    protected sealed override void GetCurrentValueAsFrozenCore(Freezable source)
    {
      base.GetCurrentValueAsFrozenCore(source);

      BitmapBlock customBitmapSource = (BitmapBlock)source;
      CopyCore(customBitmapSource, /*useCurrentValue*/ true, /*willBeFrozen*/ true);
    }

    /// <summary>
    ///     Copies data into a cloned instance.
    /// </summary>
    /// <param name="original">
    ///     The original instance to copy data from.
    /// </param>
    /// <param name="useCurrentValue">
    ///     Whether or not to copy the current value of expressions, or the
    ///     expressions themselves.
    /// </param>
    /// <param name="willBeFrozen">
    ///     Indicates whether or not the clone will be frozen.  If the
    ///     clone will be immediately frozen, there is no need to clone
    ///     data that is already frozen, you can just share the instance.
    /// </param>
    /// <remarks>
    ///     Override this method if you have additional non-DP state that
    ///     should be transfered to clones.
    /// </remarks>
    protected virtual void CopyCore(BitmapBlock original, bool useCurrentValue, bool willBeFrozen)
    {
    }


    #endregion Freezable


    #region public Properties



    protected BlockBitmapSource _parent; //parent object that owns this block


    public BlockBitmapSource Parent
    {
      get { return _parent; }
    }





    protected Int32Rect _bounds; //position of this image in destionation bitmap


    /// <summary>
    /// represents position and size of current BitmapBlock in destination image
    /// </summary>
    public Int32Rect Bounds
    {
      get { return _bounds; }
    }



    /// <summary>
    ///     Horizontal DPI of the bitmap.
    /// </summary>
    /// <remarks>
    ///     Derived classes can override this to specify their own value.
    /// </remarks>
    public override double DpiX
    {
      get
      {
        return 96.0;
      }
    }

    /// <summary>
    ///     Vertical DPI of the bitmap.
    /// </summary>
    /// <remarks>
    ///     Derived classes can override this to specify their own value.
    /// </remarks>
    public override double DpiY
    {
      get
      {
        return (double)96.0;
      }
    }





    /// <summary>
    ///     Pixel format of the bitmap.
    /// </summary>
    /// <remarks>
    ///     Derived classes can override this to specify their own value.
    /// </remarks>
    public override PixelFormat Format
    {
      get
      {
        return Parent.Format;
      }
    }



    protected int _pixelWidth;

    /// <summary>
    /// true width of block in pixels
    /// </summary>
    public override int PixelWidth
    {
      get
      {
        return _bounds.Width;
      }
    }




    protected int _pixelHeight;

    /// <summary>
    /// true height of block in pixels
    /// </summary>
    public override int PixelHeight
    {
      get
      {
        return _bounds.Height;
      }
    }




    /// <summary>
    /// tiff file storage height in pixels
    /// </summary>
    public int PaddingHeight
    {
      get
      {
        return _parent.TiffMetadata.BlockHeight;
      }
    }




    /// <summary>
    /// tiff file storage width in pixels
    /// </summary>
    public int PaddingWidth
    {
      get
      {
        return _parent.TiffMetadata.BlockWidth;
      }
    }





    /// <summary>
    ///     Palette of the bitmap.
    /// </summary>
    /// <remarks>
    ///     Derived classes can override this to specify their own value.
    /// </remarks>
    public override BitmapPalette Palette
    {
      get
      {
        return Parent.Palette;
      }
    }


    #endregion BitmapSource Properties


    #region BitmapSource Download


    /// <summary>
    ///     Whether or not the BitmapSource is downloading content.
    /// </summary>
    /// <remarks>
    ///     This is not applicable to all BitmapBlock classes, so
    ///     the base implementation return false.
    /// </remarks>
    public override bool IsDownloading
    {
      get
      {
        return false;
      }
    }




    /// <summary>
    ///     Raised when the downloading of content is completed.
    /// </summary>
    /// <remarks>
    ///     This is not applicable to all BitmapBlock classes, so
    ///     the base implementation does nothing.
    /// </remarks>
    public override event EventHandler DownloadCompleted
    {
      add
      {
      }

      remove
      {
      }
    }





    /// <summary>
    ///     Raised when the downloading of content has progressed.
    /// </summary>
    /// <remarks>
    ///     This is not applicable to all BitmapBlock classes, so
    ///     the base implementation does nothing.
    /// </remarks>
    public override event EventHandler<DownloadProgressEventArgs> DownloadProgress
    {
      add
      {
      }

      remove
      {
      }
    }





    /// <summary>
    ///     Raised when the downloading of content has failed.
    /// </summary>
    /// <remarks>
    ///     This is not applicable to all BitmapBlock classes, so
    ///     the base implementation throws.
    /// </remarks>
    public override event EventHandler<ExceptionEventArgs> DownloadFailed
    {
      add
      {
      }

      remove
      {
      }
    }


    #endregion BitmapSource Download


    #region BitmapSource Decode


    /// <summary>
    ///     Raised when the downloading of content has progressed.
    /// </summary>
    /// <remarks>
    ///     This is not applicable to all BitmapBlock classes, so
    ///     the base implementation does nothing.
    /// </remarks>
    public override event EventHandler<ExceptionEventArgs> DecodeFailed
    {
      add
      {
      }

      remove
      {
      }
    }


    #endregion BitmapSource Decode




    /// <summary>
    /// returns 4byte aligned (32 bit) stride
    /// that is used by windows Imaging subsystem
    /// </summary>
    /// <param name="imageWidth">pixel width</param>
    /// <param name="imageBpp">bits ber pixel</param>
    /// <returns></returns>
    public static int GetStrideLenght(int imageWidth, int imageBpp)
    {
      int scanlineStride = (((imageWidth * imageBpp) + 31) / 32) * 4;
      return scanlineStride;

    }


  }
}
